﻿////Copyright 2011 - Jonathan Allen

//using System;
//using System.Linq;
//using System.Windows;
//using System.Windows.Input;
//using System.Windows.Interactivity;
//using Granite.Xaml;

//namespace Granite.Xaml.Behaviors
//{
//    /// <summary>
//    /// This fires a FocusChanged Command whenever the focus is changed to a different control within the same visual tree AND that control isn't a child of this one.
//    /// This will not fire when something in a different visual tree such as a popup gets the focus.
//    /// </summary>
//    /// <remarks> 
//    /// This was created to support auto-save and auto-hide behaviors. For example, when a user control loses the focus you may want to automatically save its data and/or hide it, but you don't want to do that just because a popup or modal window temporarily stole the focus. 
//    /// </remarks>
//    public sealed partial class FocusChangedCommandBehavior : Behavior<FrameworkElement>
//    {
//		/// <summary>
//		/// Parameter for the command that will be executed
//		/// </summary>
//		public static readonly DependencyProperty CommandParameterProperty =
//            DependencyProperty.Register("CommandParameter", typeof(object), typeof(ClickCommandBehavior), new PropertyMetadata(null));

//		/// <summary>
//		/// Command that will be executed
//		/// </summary>
//		public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(ClickCommandBehavior), new PropertyMetadata(null, OnCommandChanged));

//        bool m_CurrentlyWatching;

//        FrameworkElement m_VisualRooot;

//		/// <summary>
//		/// Command that will be executed
//		/// </summary>
//		public ICommand Command
//        {
//            get { return (ICommand)AssociatedObject.GetValue(CommandProperty); }
//            set { AssociatedObject.SetValue(CommandProperty, value); }
//        }

//		/// <summary>
//		/// Parameter for the command that will be executed
//		/// </summary>
//		public object CommandParameter
//        {
//            get { return (object)AssociatedObject.GetValue(CommandParameterProperty); }
//            set { AssociatedObject.SetValue(CommandParameterProperty, value); }
//        }

//		/// <summary>
//		/// Command that will be executed
//		/// </summary>
//		public static ICommand GetCommand(FrameworkElement control)
//        {
//            if (control == null)
//                throw new ArgumentNullException("control", "control is null.");

//            return (ICommand)control.GetValue(CommandProperty);
//        }

//		/// <summary>
//		/// Parameter for the command that will be executed
//		/// </summary>
//		public static object GetCommandParameter(FrameworkElement control)
//        {
//            if (control == null)
//                throw new ArgumentNullException("control", "control is null.");

//            return control.GetValue(CommandParameterProperty);
//        }

//		/// <summary>
//		/// Command that will be executed
//		/// </summary>
//		public static void SetCommand(FrameworkElement control, ICommand value)
//        {
//            if (control == null)
//                throw new ArgumentNullException("control", "control is null.");

//            control.SetValue(CommandProperty, value);
//        }

//		/// <summary>
//		/// Parameter for the command that will be executed
//		/// </summary>
//		public static void SetCommandParameter(FrameworkElement control, object value)
//        {
//            if (control == null)
//                throw new ArgumentNullException("control", "control is null.");

//            control.SetValue(CommandParameterProperty, value);
//        }

//		/// <summary>
//		/// 
//		///             Called after the behavior is attached to an AssociatedObject.
//		///             
//		/// </summary>
//		/// <remarks>Override this to hook up functionality to the AssociatedObject.</remarks>
//        protected override void OnAttached()
//        {
//            AssociatedObject.GotFocus += AssociatedObject_GotFocus;
//            AssociatedObject.Loaded += AssociatedObject_Loaded;
//            AssociatedObject.Unloaded -= AssociatedObject_Unloaded;

//            if (VisualTreeExtensions.ControlOrChildHasFocus(AssociatedObject))
//                BeginWatch();
//        }

//		/// <summary>
//		/// 
//		///             Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
//		///             
//		/// </summary>
//		/// <remarks>Override this to unhook functionality from the AssociatedObject.</remarks>
//        protected override void OnDetaching()
//        {
//            AssociatedObject.GotFocus -= AssociatedObject_GotFocus;
//            AssociatedObject.Loaded -= AssociatedObject_Loaded;
//            AssociatedObject.Unloaded -= AssociatedObject_Unloaded;

//            EndWatch();
//        }

//        void AssociatedObject_GotFocus(object sender, RoutedEventArgs e)
//        {
//            BeginWatch();
//        }

//        void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
//        {
//            if (VisualTreeExtensions.ControlOrChildHasFocus(AssociatedObject))
//                BeginWatch();
//        }

//        /// <summary>
//        /// We cannot watch for focus change events while not loaded.
//        /// </summary>
//        /// <param name="sender"></param>
//        /// <param name="e"></param>
//        void AssociatedObject_Unloaded(object sender, RoutedEventArgs e)
//        {
//            EndWatch();
//        }

//        /// <summary>
//        /// Begin watching for focus changed events.
//        /// </summary>
//        void BeginWatch()
//        {
//            if (!m_CurrentlyWatching)
//            {
//                m_VisualRooot = (FrameworkElement)VisualTreeExtensions.FindRoot(AssociatedObject);
//                m_VisualRooot.GotFocus += VisualRooot_GotFocus;
//                m_CurrentlyWatching = true;
//            }
//        }

//        /// <summary>
//        /// Stop watching for focus changed events.
//        /// </summary>
//        void EndWatch()
//        {
//            if (m_CurrentlyWatching)
//            {
//                m_VisualRooot.GotFocus -= VisualRooot_GotFocus;
//                m_VisualRooot = null;
//                m_CurrentlyWatching = false;
//            }
//        }

//        static void OnCommandChanged(DependencyObject control, DependencyPropertyChangedEventArgs e)
//        {
//            var behaviors = Interaction.GetBehaviors(control);
//            var existingBehavior = behaviors.OfType<FocusChangedCommandBehavior>().FirstOrDefault();

//            if (e.NewValue == null)
//            {
//                if (existingBehavior != null)
//                    behaviors.Remove(existingBehavior);
//            }
//            else
//                behaviors.Add(new FocusChangedCommandBehavior());
//        }

//        void VisualRooot_GotFocus(object sender, RoutedEventArgs e)
//        {
//            if (VisualTreeExtensions.ControlOrChildHasFocus(AssociatedObject)) //we still have the focus
//                return;

//#if SILVERLIGHT
//            var currentFocus = (DependencyObject)FocusManager.GetFocusedElement();
//#else
//            var currentFocus = (DependencyObject)FocusManager.GetFocusedElement(FocusManager.GetFocusScope(AssociatedObject));
//#endif

//            if (currentFocus == null) //nothing has the focus
//                return;

//            if (VisualTreeExtensions.FindRoot(currentFocus) != m_VisualRooot) //we are in a different visual tree
//                return;

//            EndWatch(); //Don't watch again until we regain the focus

//            if (Command.CanExecute(CommandParameter))
//                Command.Execute(CommandParameter);
//        }

//    }

//}
